#include "cpp_generator.h"
#include "pp_utils.h"
#include "pp_generator.h"

#include <sstream>
#include <iostream>
#include <map>
#include <algorithm>

#define PP_GEN_CPP_VERSION "1.0.2"

namespace pp
{
    const std::map<std::string, std::string> TYPES_MAP = {
        {"uint8", "uint8_t"}, {"int8", "int8_t"},
        {"uint16", "uint16_t"}, {"int16", "int16_t"},
        {"uint32", "uint32_t"}, {"int32", "int32_t"},
        {"uint64", "uint64_t"}, {"int64", "int64_t"},
        {"float32", "float"}, {"float64", "double"},
        {"float", "float"}, {"double", "double"},
        {"string", "std::string"},
    };

    const std::map<std::string, std::string> TYPES_MEMBER_PREFIX = {
        {"uint8", "u8"}, {"int8", "i8"},
        {"uint16", "u16"}, {"int16", "i16"},
        {"uint32", "u32"}, {"int32", "i32"},
        {"uint64", "u64"}, {"int64", "i64"},
        {"float32", "f32"}, {"float64", "f64"},
        {"float", "f32"}, {"double", "f64"},
        {"string", "s"}, {"array", "a"},
    };

    void CppGenerator::Reset(const std::string& srcfile)
    {
        CodeGenerator::Reset(srcfile);
        m_sNameSpace = "";
    }

    void CppGenerator::HandleImport(const std::string& imports)
    {
        std::string srcfile = m_sSrcDir + "/" + imports;
        std::shared_ptr<CppGenerator> cppGen = std::make_shared<CppGenerator>(m_sSrcDir, m_sOutDir);
        std::shared_ptr<CodeGenerator> gen = cppGen;
        std::shared_ptr<CodeHandler> hdr = std::make_shared<CodeHandler>(gen);
        Parser parser;
        parser.SetHandler(hdr);
        cppGen->Reset(srcfile);
        parser.ParseFile(srcfile);
        m_oImports.push_back(cppGen->GetHeadFile());
        // 常量映射
        for (auto& iter : cppGen->GetConstMap())
        {
            m_oConstMap[cppGen->GetPackage() + "." + iter.first] = iter.second;
        }
    }

    void CppGenerator::HandleOption(const std::string& name, const std::string& value)
    {
        if (name == "cpp_package")
        {
            m_sNameSpace = value;
        }
    }

    void CppGenerator::HandleConst(const std::shared_ptr<FieldInfo>& fieldInfo)
    {
        CodeGenerator::HandleConst(fieldInfo);
        // 常量缓存
        m_oConstMap[fieldInfo->GetName()] = GetNameSpace() + "::" + fieldInfo->GetName();
    }

    // 处理pp文件中的enum定义
    void CppGenerator::HandleEnum(const std::shared_ptr<StructInfo>& structInfo)
    {
        CodeGenerator::HandleEnum(structInfo);
        // 常量缓存
        for (auto& v : structInfo->GetFields())
        {
            m_oConstMap[v->GetName()] = GetNameSpace() + "::" + v->GetName();
        }
    }

    // 处理pp文件中的message定义
    void CppGenerator::HandleStruct(const std::shared_ptr<StructInfo>& structInfo)
    {
        CodeGenerator::HandleStruct(structInfo);
        m_oConstMap[structInfo->GetName()] = GetNameSpace() + "::" + structInfo->GetName();
    }

    // 返回生成的文件名
    std::string CppGenerator::GetHeadFile()
    {
        std::string filename = GetFileName(m_sSrcFile);
        std::string relpath = GetRelativePath(m_sSrcDir, m_sSrcFile) + ToLower(Replace(GetNameSpace(), ".", "/"));
        return relpath + "/" + filename + ".h";
    }

    void CppGenerator::Generate()
    {
        std::string filename = GetFileName(m_sSrcFile);
        std::string relpath = GetRelativePath(m_sSrcDir, m_sSrcFile) + ToLower(Replace(GetNameSpace(), ".", "/"));
        std::string outpath = m_sOutDir + "/" + relpath + "/";

        try
        {
            CreateDirectories(outpath);
            // 生成头文件
            std::cout << "    --> " << outpath << filename << ".h" << std::endl;
            GenerateHeadFile(outpath, filename);
            std::cout << "    --> " << outpath << filename << ".cpp" << std::endl;
            GenerateCppFile(outpath, filename);
        }
        catch (const std::exception& e)
        {
            std::cerr << M_ERR_COLOR_START "error: generate source code for file '" << m_sSrcFile << "' fail:"
                << e.what() << M_ERR_COLOR_END << std::endl;
        }
    }

    // 生成头文件内容
    void CppGenerator::GenerateHeadFile(const std::string& outdir, const std::string& filename)
    {
        std::string headfile = outdir + filename + ".h";

        // 打开文件
        std::ofstream ofs(headfile, std::ios::out | std::ios::trunc);

        if (!ofs.is_open())
        {
            std::cerr << M_ERR_COLOR_START << "error: fail to open file '" << headfile
                << "' to write" << M_ERR_COLOR_END << std::endl;
            return;
        }

        ofs << "// Code generated by pp_gen_cpp. DO NOT EDIT." << std::endl
            << "// versions:" << std::endl
            << "//     pp_gen_cpp " PP_GEN_CPP_VERSION << std::endl
            << "//     pp_gen     " PP_GEN_VERSION << std::endl
            << "// source: " << TrimPath(m_sSrcFile) << std::endl << std::endl;

        GenerateHeadMacro(ofs, filename);
        GenerateHeadImport(ofs);
        GenerateNamespace(ofs);
        GenerateHeadClassDeclare(ofs);
        GenerateHeadConst(ofs);
        GenerateHeadEnum(ofs);
        GenerateHeadClass(ofs);

        // 头文件结尾
        if (!GetNameSpace().empty()) ofs << "};" << std::endl << std::endl;
        ofs << "#endif" << std::endl;

        ofs.close();
    }

    // 头文件宏定义
    void CppGenerator::GenerateHeadMacro(std::ofstream& ofs, const std::string& filename)
    {
        std::string fmacro = GetFileMacro(filename);
        ofs << "#ifndef " << fmacro << "_H" << std::endl
            << "#define " << fmacro << "_H" << std::endl << std::endl;
    }

    // 头文件include
    void CppGenerator::GenerateHeadImport(std::ofstream& ofs)
    {
        if (m_oImports.empty())
        {
            ofs << "#include \"pp/message.h\"" << std::endl << std::endl;
        }
        else
        {
            for (auto& v: m_oImports)
            {
                ofs << "#include \"" << v << "\"" << std::endl;
            }
            ofs << std::endl;
        }
    }

    // 头文件类声明
    void CppGenerator::GenerateHeadClassDeclare(std::ofstream& ofs)
    {
        std::string nsi = GetNameSpaceIndentation();
        for (auto& v: m_oStructs)
        {
            ofs << nsi << "class " << v->GetName() << ";" << std::endl;
        }

        if (!m_oStructs.empty()) ofs << std::endl;
    }

    // 头文件宏定义
    void CppGenerator::GenerateHeadConst(std::ofstream& ofs)
    {
        std::string nsi = GetNameSpaceIndentation();
        std::vector<std::string> clist;
        uint32_t maxlen = 0;

        // 以下逻辑的目的，先算出const的最大长度，目的是为了对齐注释
        for (auto& v: m_oConsts)
        {
            std::string qoutes = v->GetType() == "string" ? "\"" : "";
            std::stringstream ss;
            ss << nsi << "const " << GetClassType(v->GetType()) << " " << v->GetName() << " = "
                << qoutes << v->GetValue() << qoutes << ";";
            std::string sval = ss.str();
            if (sval.length() > maxlen) maxlen = sval.length();
            clist.push_back(sval);
        }

        // 对齐注释，输出到文件
        for (size_t i = 0; i < clist.size(); i++)
        {
            auto v = m_oConsts[i];
            std::string sval = clist[i];

            ofs << sval;
            if (!v->GetDesc().empty())
            {
                for (size_t j = 0; j < maxlen - sval.size(); j++) ofs << " ";
                ofs << "    // " << v->GetDesc();
            }
            ofs << std::endl;
        }

        if (!m_oConsts.empty()) ofs << std::endl;
    }

    // 头文件枚举定义
    void CppGenerator::GenerateHeadEnum(std::ofstream& ofs)
    {
        std::string nsi = GetNameSpaceIndentation();

        for (auto& v : m_oEnums)
        {
            if (!v->GetDesc().empty()) ofs << nsi << "// " << v->GetDesc() << std::endl;
            ofs << nsi << "enum " << v->GetName() << std::endl
                << nsi << "{" << std::endl;
            GenerateHeadEnumValues(ofs, v->GetFields());
            ofs << nsi << "};" << std::endl << std::endl;
        }
    }

    // 头文件枚举值
    void CppGenerator::GenerateHeadEnumValues(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        std::string nsi = GetNameSpaceIndentation();
        std::vector<std::string> clist;
        uint32_t maxlen = 0;

        // 以下逻辑的目的，先算出最大长度，目的是为了对齐注释
        for (auto& v: vals)
        {
            std::stringstream ss;
            ss << nsi << CODE_INDENTATION << v->GetName() << " = " << v->GetValue() << ",";
            std::string sval = ss.str();
            if (sval.length() > maxlen) maxlen = sval.length();
            clist.push_back(sval);
        }

        // 对齐注释，输出到文件
        for (size_t i = 0; i < clist.size(); i++)
        {
            auto v = vals[i];
            std::string sval = clist[i];

            ofs << sval;
            if (!v->GetDesc().empty())
            {
                for (size_t j = 0; j < maxlen - sval.size(); j++) ofs << " ";
                ofs << "    // " << v->GetDesc();
            }
            ofs << std::endl;
        }
    }

    // 头文件消息类定义
    void CppGenerator::GenerateHeadClass(std::ofstream& ofs)
    {
        std::string nsi = GetNameSpaceIndentation();
        int i = 0;

        for (auto& v : m_oStructs)
        {
            std::string className = v->GetName();

            if (i++ > 0) ofs << std::endl;

            if (!v->GetDesc().empty()) ofs << nsi << "// " << v->GetDesc() << std::endl;
            ofs << nsi << "class " << className << " : public pp::Message" << std::endl
                << nsi << "{" << std::endl;
            // 类成员定义
            GenerateHeadClassAttributes(ofs, v->GetFields());
            // 构造函数
            ofs << nsi << "public:" << std::endl
                << nsi << CODE_INDENTATION << "// constructor" << std::endl
                << nsi << CODE_INDENTATION << className << "();" << std::endl;
            // geter/setter函数
            GenerateHeadClassMemberFunctions(ofs, v->GetFields());
            // 编码解码函数
            ofs << nsi << "public:" << std::endl
                << nsi << CODE_INDENTATION << "int Encode(pp::ByteArray& buf, uint64_t tag);" << std::endl
                << nsi << CODE_INDENTATION << "std::string ToJson() const;" << std::endl
                << nsi << CODE_INDENTATION << "std::string ToString() const;" << std::endl
                << nsi << "protected:" << std::endl
                << nsi << CODE_INDENTATION << "int DecodeSubField(uint64_t tag, const char* buf, uint32_t len);" << std::endl;

            ofs << nsi << "};" << std::endl;
        }
    }

    // 头文件消息类成员定义
    void CppGenerator::GenerateHeadClassAttributes(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        if (vals.empty()) return;

        std::string nsi = GetNameSpaceIndentation();
        ofs << nsi << "private:" << std::endl;

        std::vector<std::string> clist;
        uint32_t maxlen = 0;

        // 以下逻辑的目的，先算出最大长度，目的是为了对齐注释
        for (auto& v: vals)
        {
            std::stringstream ss;
            ss << nsi << CODE_INDENTATION << GetClassAttribute(v->GetType(), v->GetSubType(), ToPascalCase(v->GetName()));
            std::string sval = ss.str();
            if (sval.length() > maxlen) maxlen = sval.length();
            clist.push_back(sval);
        }

        // 对齐注释，输出到文件
        for (size_t i = 0; i < clist.size(); i++)
        {
            auto v = vals[i];
            std::string sval = clist[i];

            ofs << sval;
            if (!v->GetDesc().empty())
            {
                for (size_t j = 0; j < maxlen - sval.size(); j++) ofs << " ";
                ofs << "    // " << v->GetDesc();
            }
            ofs << std::endl;
        }
    }

    // 头文件消息类成员Get/Set函数
    void CppGenerator::GenerateHeadClassMemberFunctions(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        if (vals.empty()) return;

        std::string nsi = GetNameSpaceIndentation();
        ofs << nsi << "public:" << std::endl;

        for (auto& v: vals)
        {
            std::string attrName = ToPascalCase(v->GetName());
            std::string memberName = GetClassAttributeName(v->GetType(), v->GetSubType(), attrName);

            if (!v->GetDesc().empty()) ofs << nsi << CODE_INDENTATION << "// " << v->GetDesc() << std::endl;
            if (v->GetType() == "string")
            {
                ofs << nsi << CODE_INDENTATION << "void Set" << attrName << "(const std::string& v) {" << memberName
                    << " = v;}" << std::endl;
                ofs << nsi << CODE_INDENTATION << "const std::string& Get" << attrName << "() const {return " << memberName
                    << ";}" << std::endl;
            }
            else if (v->GetType() == "array")
            {
                auto iter = TYPES_MAP.find(v->GetSubType());
                if (iter != TYPES_MAP.end())
                {
                    std::string param = v->GetSubType() == "string" ? "const std::string&" : iter->second;
                    ofs << nsi << CODE_INDENTATION << "void Add" << attrName << "(" << param << " v) {" << memberName
                        << ".push_back(v);}" << std::endl;
                    ofs << nsi << CODE_INDENTATION << "const std::vector<" << iter->second << ">& Get" << attrName
                        << "() const {return " << memberName << ";}" << std::endl;
                    ofs << nsi << CODE_INDENTATION << "std::vector<" << iter->second << ">& Get" << attrName
                        << "() {return " << memberName << ";}" << std::endl;
                }
                else
                {
                    std::string ftype = GetImportValue(v->GetSubType());
                    ofs << nsi << CODE_INDENTATION << "void Add" << attrName << "(std::shared_ptr<"
                        << ftype << ">& v) {" << memberName << ".push_back(v);}" << std::endl;
                    ofs << nsi << CODE_INDENTATION << "std::shared_ptr<" << ftype << "> Add" << attrName << "() {"
                        << "PP_ARRAY_ADD_FIELD(" << ftype << ", " << memberName << ");}" << std::endl;
                    ofs << nsi << CODE_INDENTATION << "const std::vector<std::shared_ptr<" << ftype
                        << "> >& Get" << attrName << "() const {return " << memberName << ";}" << std::endl;
                    ofs << nsi << CODE_INDENTATION << "std::vector<std::shared_ptr<" << ftype
                        << "> >& Get" << attrName << "() {return " << memberName << ";}" << std::endl;
                }
            }
            else
            {
                auto iter = TYPES_MAP.find(v->GetType());
                if (iter != TYPES_MAP.end())
                {
                    ofs << nsi << CODE_INDENTATION << "void Set" << attrName << "(" << iter->second << " v) {" << memberName
                        << " = v;}" << std::endl;
                    ofs << nsi << CODE_INDENTATION << iter->second << " Get" << attrName << "() const {return " << memberName
                        << ";}" << std::endl;
                }
                else
                {
                    std::string ftype = GetImportValue(v->GetType());
                    ofs << nsi << CODE_INDENTATION << "void Set" << attrName << "(std::shared_ptr<" << ftype << ">& v) {" << memberName
                        << " = v;}" << std::endl;
                    ofs << nsi << CODE_INDENTATION << "const std::shared_ptr<" << ftype << ">& Get" << attrName << "() const {return " << memberName
                        << ";}" << std::endl;
                    ofs << nsi << CODE_INDENTATION << "std::shared_ptr<" << ftype << ">& Get" << attrName << "() {return " << memberName
                        << ";}" << std::endl;
                    ofs << nsi << CODE_INDENTATION << "// Get the object. if the object is null, create the object and return it." << std::endl;
                    ofs << nsi << CODE_INDENTATION << "std::shared_ptr<" << ftype << ">& Obtain" << attrName << "() {PP_OBTAIN_FIELD("
                        << ftype << ", " << memberName << ");}" << std::endl;
                }
            }
        }
    }

    // 生成实现文件内容
    void CppGenerator::GenerateCppFile(const std::string& outdir, const std::string& filename)
    {
        std::string cppfile = outdir + filename + ".cpp";

        // 打开文件
        std::ofstream ofs(cppfile, std::ios::out | std::ios::trunc);

        if (!ofs.is_open())
        {
            std::cerr << M_ERR_COLOR_START << "error: fail to open file '" << cppfile
                << "' to write" << M_ERR_COLOR_END << std::endl;
            return;
        }

        ofs << "// Code generated by pp_gen_cpp. DO NOT EDIT." << std::endl
            << "// versions:" << std::endl
            << "//     pp_gen_cpp " PP_GEN_CPP_VERSION << std::endl
            << "//     pp_gen     " PP_GEN_VERSION << std::endl
            << "// source: " << TrimPath(m_sSrcFile) << std::endl << std::endl
            << "#include \"" << filename << ".h\"" << std::endl << std::endl
            << "#include <sstream>" << std::endl << std::endl;

        GenerateNamespace(ofs);
        GenerateCppClass(ofs);

        // cpp文件结尾
        if (!GetNameSpace().empty()) ofs << "};" << std::endl;

        ofs.close();
    }

    // CPP文件类实现函数
    void CppGenerator::GenerateCppClass(std::ofstream& ofs)
    {
        std::string nsi = GetNameSpaceIndentation();
        int i = 0;

        for (auto& v : m_oStructs)
        {
            std::string className = v->GetName();

            if (i++ > 0) ofs << std::endl;

            if (!v->GetDesc().empty()) ofs << nsi << "// " << v->GetDesc() << std::endl;
            // 构造函数
            ofs << nsi << "// constructor" << std::endl
                << nsi << className << "::" << className << "()" << std::endl;
            GenerateCppClassConstructor(ofs, v->GetFields());
            ofs << nsi << "{" << std::endl
                << nsi << "}" << std::endl << std::endl;

            // 编码函数
            ofs << nsi << "int " << className << "::Encode(pp::ByteArray& buf, uint64_t tag)" << std::endl
                << nsi << "{" << std::endl;
            GenerateCppClassEncodeFunction(ofs, v->GetFields());
            ofs << nsi << CODE_INDENTATION << "return 0;" << std::endl
                << nsi << "}" << std::endl << std::endl;

            // 解码函数
            ofs << nsi << "int " << className << "::DecodeSubField(uint64_t tag, const char* buf, uint32_t len)" << std::endl
                << nsi << "{" << std::endl;
            GenerateCppClassDecodeFunction(ofs, v->GetFields());
            ofs << nsi << CODE_INDENTATION << "return 0;" << std::endl
                << nsi << "}" << std::endl << std::endl;

            // ToJson
            ofs << nsi << "std::string " << className << "::ToJson() const" << std::endl
                << nsi << "{" << std::endl;
            GenerateCppClassToJsonFunction(ofs, v->GetFields());
            ofs << nsi << CODE_INDENTATION << "return \"{\" + pp::TrimLast(ss.str(), ',') + \"}\";" << std::endl
                << nsi << "}" << std::endl << std::endl;

            // ToString
            ofs << nsi << "std::string " << className << "::ToString() const" << std::endl
                << nsi << "{" << std::endl;
            GenerateCppClassToStringFunction(ofs, v->GetFields());
            ofs << nsi << CODE_INDENTATION << "return \"{\" + pp::TrimLast(ss.str(), ',') + \"}\";" << std::endl
                << nsi << "}" << std::endl;
        }
    }

    // CPP文件构造函数
    void CppGenerator::GenerateCppClassConstructor(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        if (vals.empty()) return;

        std::string nsi = GetNameSpaceIndentation();
        std::stringstream ss;
        int i = 0;

        for (auto& v: vals)
        {
            auto iter = TYPES_MAP.find(v->GetType());
            if (iter == TYPES_MAP.end()) continue;

            if (v->GetType() == "string" && v->GetDefault().empty()) continue;

            std::string attrName = ToPascalCase(v->GetName());
            std::string memberName = GetClassAttributeName(v->GetType(), v->GetSubType(), attrName);
            std::string indent = (i == 0 ? ":" : " ");
            if (i > 0) ss << "," << std::endl;

            ss << nsi << CODE_INDENTATION;
            ss << indent;

            if (v->GetType() == "string")
            {
                ss << " " << memberName << "(" << GetImportValue(v->GetDefault(), true) << ")";
            }
            else
            {
                std::string def = v->GetDefault().empty() ? "0" : GetImportValue(v->GetDefault());
                ss << " " << memberName << "(" << def << ")";
            }
            i++;
        }

        std::string s = ss.str();
        if (!s.empty()) ofs << s << std::endl;
    }

    // CPP文件编码函数
    void CppGenerator::GenerateCppClassEncodeFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        if (vals.empty()) return;

        std::string nsi = GetNameSpaceIndentation();
        ofs << nsi << CODE_INDENTATION << "// Encode sub field" << std::endl
            << nsi << CODE_INDENTATION << "pp::ByteArray subBuf(128);" << std::endl;

        for (auto& v: vals)
        {
            std::string attrName = ToPascalCase(v->GetName());
            std::string memberName = GetClassAttributeName(v->GetType(), v->GetSubType(), attrName);

            if (v->GetType() == "array")
            {
                auto iter = TYPES_MAP.find(v->GetSubType());
                if (iter != TYPES_MAP.end())
                {
                    ofs << nsi << CODE_INDENTATION << "PP_ARRAY_FIELD_ENCODE(" << memberName << ", subBuf, "
                        << GetImportValue(v->GetTag()) << ", " << iter->second << ");" << std::endl;
                }
                else
                {
                    std::string ftype = GetImportValue(v->GetSubType());
                    ofs << nsi << CODE_INDENTATION << "PP_ARRAY_STRUCT_ENCODE(" << memberName << ", subBuf, "
                        << GetImportValue(v->GetTag()) << ", std::shared_ptr<" << ftype << ">);" << std::endl;
                }
            }
            else
            {
                auto iter = TYPES_MAP.find(v->GetType());
                if (iter != TYPES_MAP.end())
                {
                    ofs << nsi << CODE_INDENTATION << "pp::FieldEncode(subBuf, " << GetImportValue(v->GetTag()) << ", "
                        << memberName << ");" << std::endl;
                }
                else
                {
                    ofs << nsi << CODE_INDENTATION << "if (" << memberName << ") "
                        << memberName << "->Encode(subBuf, " << GetImportValue(v->GetTag()) << ");" << std::endl;
                }
            }
        }

        ofs << nsi << CODE_INDENTATION << "// Encode the entire field" << std::endl
            << nsi << CODE_INDENTATION << "buf.AppendVarint(tag).AppendVarint(subBuf.Length()).Append(subBuf.Data(), subBuf.Length());" << std::endl;
    }

    // CPP文件解码函数
    void CppGenerator::GenerateCppClassDecodeFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        if (vals.empty()) return;

        std::string nsi = GetNameSpaceIndentation();
        ofs << nsi << CODE_INDENTATION << "switch (tag)" << std::endl
            << nsi << CODE_INDENTATION << "{" << std::endl;

        for (auto& v: vals)
        {
            std::string attrName = ToPascalCase(v->GetName());
            std::string memberName = GetClassAttributeName(v->GetType(), v->GetSubType(), attrName);

            if (v->GetType() == "array")
            {
                auto iter = TYPES_MAP.find(v->GetSubType());
                if (iter != TYPES_MAP.end())
                {
                    ofs << nsi << CODE_INDENTATION << "case " << GetImportValue(v->GetTag()) << ":" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << "{" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << CODE_INDENTATION << iter->second << " val;" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << CODE_INDENTATION << "PP_FUNC_RET(pp::FieldDecode(buf, len,  val));" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << CODE_INDENTATION << memberName << ".push_back(val);" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << "}" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << "break;" << std::endl;
                }
                else
                {
                    std::string ftype = GetImportValue(v->GetSubType());
                    ofs << nsi << CODE_INDENTATION << "case " << GetImportValue(v->GetTag()) << ":" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << "{" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << CODE_INDENTATION
                        << "std::shared_ptr<" << ftype << "> val = std::make_shared<" << ftype << ">();" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << CODE_INDENTATION << "PP_FUNC_RET(val->Decode(buf, len, 0));" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << CODE_INDENTATION << memberName << ".push_back(val);" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << "}" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << "break;" << std::endl;
                }
            }
            else
            {
                auto iter = TYPES_MAP.find(v->GetType());
                if (iter != TYPES_MAP.end())
                {
                    ofs << nsi << CODE_INDENTATION << "case " << GetImportValue(v->GetTag()) << ":" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION
                        << "PP_FUNC_RET(pp::FieldDecode(buf, len, " << memberName << "));" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << "break;" << std::endl;
                }
                else
                {
                    ofs << nsi << CODE_INDENTATION << "case " << GetImportValue(v->GetTag()) << ":" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << "PP_FUNC_RET(Obtain" << attrName
                        << "()->Decode(buf, len, 0));" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << "break;" << std::endl;
                }
            }
        }

        ofs << nsi << CODE_INDENTATION << "default:" << std::endl
            << nsi << CODE_INDENTATION << CODE_INDENTATION << "break;" << std::endl
            << nsi << CODE_INDENTATION << "}" << std::endl;
    }

    // CPP文件ToJson函数
    void CppGenerator::GenerateCppClassToJsonFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        std::string nsi = GetNameSpaceIndentation();
        ofs << nsi << CODE_INDENTATION << "std::stringstream ss;" << std::endl << std::endl;

        int i = 0;
        std::string sif;

        for (auto& v: vals)
        {
            std::string jsonName = v->GetJsonName().empty() ? v->GetName() : v->GetJsonName();
            std::string attrName = ToPascalCase(v->GetName());
            std::string memberName = GetClassAttributeName(v->GetType(), v->GetSubType(), attrName);

            if (i > 0)
            {
                if (sif.empty())
                {
                    ofs << nsi << CODE_INDENTATION << "ss << " << " \",\";" << std::endl;
                }
                else
                {
                    ofs << " << " << " \",\";" << std::endl;
                }
            }
            sif = "";
            i++;

            if (v->GetType() == "array")
            {
                auto iter = TYPES_MAP.find(v->GetSubType());
                if (iter != TYPES_MAP.end())
                {
                    ofs << nsi << CODE_INDENTATION << "PP_ARRAY_FIELD_TOJSON(ss, " << memberName << ", \""
                        << jsonName << "\");" << std::endl;
                }
                else
                {
                    ofs << nsi << CODE_INDENTATION << "PP_ARRAY_STRUCT_TOJSON(ss, " << memberName << ", \""
                        << jsonName << "\");" << std::endl;
                }
            }
            else
            {
                auto iter = TYPES_MAP.find(v->GetType());
                if (iter != TYPES_MAP.end())
                {
                    ofs << nsi << CODE_INDENTATION << "pp::FieldToJson(ss, \"" << jsonName << "\", "
                        << memberName << ");" << std::endl;
                }
                else
                {
                    sif = "if (" + memberName + ") ";
                    ofs << nsi << CODE_INDENTATION << sif << "ss << \"\\\"" << jsonName << "\\\":\" << " << memberName
                        << "->ToJson()";
                }
            }
        }

        if (!sif.empty()) ofs << ";" << std::endl;
    }

    // CPP文件ToJson函数
    void CppGenerator::GenerateCppClassToStringFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        std::string nsi = GetNameSpaceIndentation();
        ofs << nsi << CODE_INDENTATION << "std::stringstream ss;" << std::endl << std::endl;

        int i = 0;
        std::string sif;

        for (auto& v: vals)
        {
            std::string jsonName = v->GetJsonName().empty() ? v->GetName() : v->GetJsonName();
            std::string attrName = ToPascalCase(v->GetName());
            std::string memberName = GetClassAttributeName(v->GetType(), v->GetSubType(), attrName);

            if (i > 0)
            {
                if (sif.empty())
                {
                    ofs << nsi << CODE_INDENTATION << "ss << " << " \",\";" << std::endl;
                }
                else
                {
                    ofs << " << " << " \",\";" << std::endl;
                }
            }
            sif = "";
            i++;

            if (v->GetType() == "array")
            {
                auto iter = TYPES_MAP.find(v->GetSubType());
                if (iter != TYPES_MAP.end())
                {
                    ofs << nsi << CODE_INDENTATION << "PP_ARRAY_FIELD_TOSTRING(ss, " << memberName << ", \""
                        << jsonName << "\");" << std::endl;
                }
                else
                {
                    ofs << nsi << CODE_INDENTATION << "PP_ARRAY_STRUCT_TOSTRING(ss, " << memberName << ", \""
                        << jsonName << "\");" << std::endl;
                }
            }
            else
            {
                auto iter = TYPES_MAP.find(v->GetType());
                if (iter != TYPES_MAP.end())
                {
                    ofs << nsi << CODE_INDENTATION << "pp::FieldToString(ss, \"" << jsonName << "\", "
                        << memberName << ");" << std::endl;
                }
                else
                {
                    sif = "if (" + memberName + ") ";
                    ofs << nsi << CODE_INDENTATION << sif << "ss << \"" << jsonName << ":\" << " << memberName
                        << "->ToString()";
                }
            }
        }

        if (!sif.empty()) ofs << ";" << std::endl;
    }

    // 命名空间
    void CppGenerator::GenerateNamespace(std::ofstream& ofs)
    {
        std::string ns = GetNameSpace();
        if (!ns.empty()) ofs << "namespace " << ns << std::endl << "{" << std::endl;
    }

    std::string CppGenerator::GetFileMacro(const std::string& filename)
    {
        std::stringstream result;
        for (size_t i = 0; i < filename.length(); i++)
        {
            char ch = filename.at(i);
            if (ch >= 'a' && ch <= 'z')
            {
                char u = std::toupper(ch);
                result << u;
            }
            else if ((ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))
            {
                result << ch;
            }
            else
            {
                result << "_";
            }
        }
        return result.str();
    }

    // 返回数据类型
    std::string CppGenerator::GetClassType(const std::string& ftype)
    {
        auto iter = TYPES_MAP.find(ftype);
        if (iter != TYPES_MAP.end()) return iter->second;
        return GetImportValue(ftype);
    }

    // 返回类成员定义
    std::string CppGenerator::GetClassAttribute(const std::string& ftype, const std::string& subtype, const std::string& name)
    {
        std::string memberName = GetClassAttributeName(ftype, subtype, name);

        if (ftype == "array")
        {
            auto iter = TYPES_MAP.find(subtype);
            if (iter != TYPES_MAP.end()) return "std::vector<" + iter->second + "> " + memberName + ";";
            return "std::vector<std::shared_ptr<" + GetImportValue(subtype) + "> > " + memberName + ";";
        }
        auto iter = TYPES_MAP.find(ftype);
        if (iter != TYPES_MAP.end())
        {
            return iter->second + " " + memberName + ";";
        }
        return "std::shared_ptr<" + GetImportValue(ftype) + "> " + memberName + ";";
    }

    // 返回类成员名
    std::string CppGenerator::GetClassAttributeName(const std::string& ftype, const std::string& subtype, const std::string& name)
    {
        auto iter = TYPES_MEMBER_PREFIX.find(ftype);
        if (iter != TYPES_MEMBER_PREFIX.end()) return "m_" + iter->second + name;
        return "m_p" + name;
    }

    // 从常量数据中返回
    std::string CppGenerator::GetImportValue(const std::string& constVal, bool bstring)
    {
        auto iter = m_oConstMap.find(constVal);
        if (iter != m_oConstMap.end()) return iter->second;
        return bstring ? "\"" + constVal + "\"" : constVal;
    }
};
